#pragma once
#include <iostream>
#include <thread>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
#include <atomic>
#include <memory>

class CameraStream
{

public:
    CameraStream(std::string streamPath);
    ~CameraStream();
    void streamLoop();
    int openStream();
    int getFrame(cv::Mat &frame);

private:
    cv::Mat frame_;
    std::atomic<bool> frameUsed_;
    std::string streamPath_;

private:
    std::shared_ptr<cv::VideoCapture> cap_;
    std::thread frameThread_;
};

CameraStream::CameraStream(std::string streamPath): streamPath_(streamPath)
{
    frameUsed_.store(true);
    cap_ = std::make_shared<cv::VideoCapture>(streamPath_);
}

CameraStream::~CameraStream()
{
    cap_->release();
}

void CameraStream::streamLoop()
{
    frameThread_ = std::thread([this]()
                               {
    cv::Mat frame;
    cap_->set(cv::VideoCaptureProperties::CAP_PROP_POS_FRAMES, 500);
    int nFrameEmpty = 0;
    while (true)
    {
        cap_->read(frame);
        if(frame.empty())
        {
            nFrameEmpty++;
            if(nFrameEmpty > 100)
            {
                cap_->open(streamPath_);
                nFrameEmpty = 0;
            }
            
        }
        if (frame.data && frameUsed_.load())
        {
            frame.copyTo(frame_);
            frameUsed_.store(false);
        }
    } });
}

int CameraStream::openStream()
{
    if (!cap_->isOpened())
    {
        std::cout << "open stream failed" << std::endl;
        return -1;
    }
    return 0;
}

int CameraStream::getFrame(cv::Mat &frame)
{
    if (!frameUsed_.load())
    {

        frame_.copyTo(frame);
        frameUsed_.store(true);
        return 0;
    }
    else
    {
        return -1;
    }
}